
<!DOCTYPE html>
<html lang="zh-CN" class="loading">
<head><meta name="generator" content="Hexo 3.9.0">
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <title>JavaScript中更简便的数组处理函数.map()，.reduce()，.filter() - 三·钻 TriDiamond</title>
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
    <meta name="google" content="notranslate">
    <meta name="keywords" content="TriDiamond Obsidian,"> 
    <meta name="description" content="如果你刚接触JavaScript可能你还没有听说过.map()，.reduce()，.filter()。或者听说过，看过别人用过但是自己在实际项目中没有用过。在国内很多开发项目都是需要考虑IE8的兼,"> 
    <meta name="author" content="三·钻 TriDiamond"> 
    <link rel="alternative" href="atom.xml" title="三·钻 TriDiamond" type="application/atom+xml"> 
    <link rel="icon" href="/img/favicon.png"> 
    <link href="https://fonts.loli.net/css?family=Roboto+Mono|Rubik&display=swap" rel="stylesheet">
    <link rel="stylesheet" href="//at.alicdn.com/t/font_1429596_nzgqgvnmkjb.css">
    <link rel="stylesheet" href="//cdn.bootcss.com/animate.css/3.7.2/animate.min.css">
    <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/social-share.js/1.0.16/css/share.min.css">
    <link rel="stylesheet" href="//cdn.bootcss.com/codemirror/5.48.4/codemirror.min.css">
    <link rel="stylesheet" href="//cdn.bootcss.com/codemirror/5.48.4/theme/dracula.css">
    <link rel="stylesheet" href="/css/obsidian.css">
    <link rel="stylesheet" href="/css/ball-atom.min.css">
</head>
</html>

<body class="loading">
    <div class="loader">
        <div class="la-ball-atom la-2x">
            <div></div>
            <div></div>
            <div></div>
            <div></div>
        </div>
    </div>
    <span id="config-title" style="display:none">三·钻 TriDiamond</span>
    <div id="loader"></div>
    <div id="single">
    <div class="scrollbar gradient-bg-rev"></div>
<div id="top" style="display: block;">
    <div class="bar" style="width: 0;"></div>
    <div class="navigation animated fadeIn fast delay-1s">
        <img id="home-icon" class="icon-home" src="/img/favicon.png" alt="" data-url="https://tridiamond.me">
        <div id="play-icon" title="Play/Pause" class="iconfont icon-play"></div>
        <h3 class="subtitle">JavaScript中更简便的数组处理函数.map()，.reduce()，.filter()</h3>
        <div class="social">
            <!--        <div class="like-icon">-->
            <!--            <a href="javascript:;" class="likeThis active"><span class="icon-like"></span><span class="count">76</span></a>-->
            <!--        </div>-->
            <div>
                <div class="share">
                    
                        <a href="javascript:;" class="iconfont icon-share1"></a>
                        <div class="share-component-cc" data-disabled="facebook,douban,linkedin,diandian,tencent,google"></div>
                    
                </div>
            </div>
        </div>
    </div>
</div>

    <div class="section">
        <div class=article-header-wrapper>
    <div class="article-header">
        <div class="article-cover animated fadeIn" style="
            animation-delay: 600ms;
            animation-duration: 1.2s;
            background-image: 
                radial-gradient(ellipse closest-side, rgba(0, 0, 0, 0.65), #100e17),
                url(https://res.cloudinary.com/tridiamond/image/upload/v1572613799/blog/simplify-your-javascript-with_acr2px.jpg);">
        </div>
        <div class="else">
            <p class="animated fadeInDown">
                
                <a href="/categories/FrontEnd"><b>「
                    </b>FRONTEND<b> 」</b></a>
                
                十一月 02, 2019
            </p>
            <h3 class="post-title animated fadeInDown"><a href="/2019/11/02/frontend/simplify-your-javascript-with.html" title="JavaScript中更简便的数组处理函数.map()，.reduce()，.filter()">JavaScript中更简便的数组处理函数.map()，.reduce()，.filter()</a>
            </h3>
            
            <p class="post-count animated fadeInDown">
                
                <span>
                    <b class="iconfont icon-text2"></b> <i>文章字数</i>
                    9.3k
                </span>
                
                
                <span>
                    <b class="iconfont icon-timer__s"></b> <i>阅读约需</i>
                    8 mins.
                </span>
                
                
                
                <span id="busuanzi_container_page_pv">
                    <b class="iconfont icon-read"></b> <i>阅读次数</i>
                    <span id="busuanzi_value_page_pv">0</span>
                </span>
                
            </p>
            
            
            <ul class="animated fadeInDown post-tags-list"><li class="animated fadeInDown post-tags-list-item"><a class="animated fadeInDown post-tags-list-link" href="/tags/ES6/">ES6</a></li><li class="animated fadeInDown post-tags-list-item"><a class="animated fadeInDown post-tags-list-link" href="/tags/JavaScript/">JavaScript</a></li></ul>
            
        </div>
    </div>
</div>

<div class="screen-gradient-after">
    <div class="screen-gradient-content">
        <div class="screen-gradient-content-inside">
            <div class="bold-underline-links screen-gradient-sponsor">
                <p>
                    <span class="animated fadeIn delay-1s"></span>
                </p>
            </div>
        </div>
    </div>
</div>

<div class="article">
    <div class='main'>
        <div class="content markdown animated fadeIn">
            <p>如果你刚接触JavaScript可能你还没有听说过<code>.map()</code>，<code>.reduce()</code>，<code>.filter()</code>。或者听说过，看过别人用过但是自己在实际项目中没有用过。在国内很多开发项目都是需要考虑IE8的兼容，为了兼容很多JavaScript好用的方法和技巧都被埋没了。但是我发现近几年开始，很多开发项目已经完全抛弃了IE这个魔鬼了。如果你不需要兼容古老的IE浏览器了，那就要开始熟悉一下这几个方法来处理数组。</p>
<blockquote>
<p>注意这遍文章说的的3个方法其实在很多其他语言都可以使用到，因为这几个方法和使用概念在很多其他语言都是存在的。</p>
</blockquote>
<hr>
<h1 id="map"><a href="#map" class="headerlink" title=".map()"></a>.map()</h1><p>让我用一个简单的例子告诉你如何使用这个方法。假如你现在有多对象的数组数据 - 每一个对象代表着一个员工的信息。现在你想要的最终结果就是取出所有员工的唯一ID值。</p>
<pre><code class="javascript">// 员工数据
var employees = [
  { id: 20, name: &#39;Captain Piett&#39; },
  { id: 24, name: &#39;General Veers&#39; },
  { id: 56, name: &#39;Admiral Ozzel&#39; },
  { id: 88, name: &#39;Commander Jerjerrod&#39; }
];
// 你想要的结果
[20, 24, 56, 88]</code></pre>
<p>其实要实现这个结果有很多数组处理方式。传统的处理方法就是先定义一个空数组，然后使用<code>.forEach()</code>，<code>.for(...of)</code>，或者是最简单的<code>.for()</code>来组装ID到你定义的数组里面。</p>
<p>我们来对比一下传统的处理方式和<code>.map()</code>的区别。</p>
<p>使用<code>.forEach()</code>：</p>
<pre><code class="javascript">var employeeIds = [];
employees.forEach(function (employee) {
  employeeIds.push(officer.id);
});</code></pre>
<p>注意使用传统的方式，我们必须有一个预定义的空数组变量才行。但是如果是<code>.map()</code>就会更简单了。</p>
<pre><code class="javascript">var employeeIds = employees.map(function (employee) {
  return employee.id
});</code></pre>
<p>甚至我们可以用更简洁的方式，使用箭头方法（但是需要ES6支持，Babel，或者TypeScript）。</p>
<pre><code class="javascript">const employeeIds = employees.map(employee =&gt; employee.id);</code></pre>
<p>所以<code>.map()</code>到底是怎么运作的呢？这个方法有两个参数，第一是回调方法，第二是可选内容（会在回调方法中做为<code>this</code>）。数组里的<code>每个数值/对象会被循环进入到回调方法</code>里面，然后<code>返回新的数值/对象</code>到结果数组里面。</p>
<p>注意的是结果数组的长度永远都会和被循环的数组的长度一致。</p>
<hr>
<h1 id="reduce"><a href="#reduce" class="headerlink" title=".reduce()"></a>.reduce()</h1><p>与<code>.map()</code>相识，<code>.reduce()</code>也是循环一个回调方法，数组里面的每一个元素对回进入回调方法。区别是回调方法返回的值会被传递到下一个回调方法，如此类推（等同于一个累加器）。</p>
<p><code>.reduce()</code>里的累加值可以是任何属性的值，包括<code>integer</code>，<code>string</code>，<code>object</code>等等。这个累加值会被实力化或者传递到下一个回调方法。</p>
<p>来上代码，做个简单的例子！假如你有一个飞机师的数组，数组里面有每个飞机师的工龄。</p>
<pre><code class="javascript">var pilots = [
  {
    id: 10,
    name: &quot;Poe Dameron&quot;,
    years: 14,
  },
  {
    id: 2,
    name: &quot;Temmin &#39;Snap&#39; Wexley&quot;,
    years: 30,
  },
  {
    id: 41,
    name: &quot;Tallissan Lintra&quot;,
    years: 16,
  },
  {
    id: 99,
    name: &quot;Ello Asty&quot;,
    years: 22,
  }
];</code></pre>
<p>现在我们需要知道所有飞机师累计的总工龄。使用<code>.reduce()</code>就是比吃饭还简单的事情。</p>
<pre><code class="javascript">var totalYears = pilots.reduce(function (accumulator, pilot) {
  return accumulator + pilot.years;
}, 0);</code></pre>
<p>注意我这里第二个参数我传了0。第二个参数是一个累加值的初始值。当然如果场景需要这个初始值也可以传入一个变量或者你需要的值。循环了数组里的每一个元素后，reduce方法会返回最终累加后的值（在我们这个例子中就是<code>82</code>）。</p>
<blockquote>
<p>例子里面的<code>acc</code>和<code>accumulator</code>就是累加值变量</p>
</blockquote>
<p>如果是使用ES6箭头写法，我们可以写的更加优雅简洁。一行就可以搞掂的事情！</p>
<pre><code class="javascript">const totalYears = pilots.reduce((acc, pilot) =&gt; acc + pilot.years, 0);</code></pre>
<p>现在如果我们需要找到哪一位是最有经验的飞机师。这种情况我们一样可以使用<code>.reduce()</code>。</p>
<pre><code class="javascript">var mostExpPilot = pilots.reduce(function (oldest, pilot) {
  return (oldest.years || 0) &gt; pilot.years ? oldest : pilot;
}, {});</code></pre>
<p>这里我把<code>accumulator</code>变量改为<code>oldest</code>代表飞机师里面的老司机。这时候reduce里面的回调方法对比每一个飞机师，每一次飞机师的值进入这个回调方法，工龄更高的就会覆盖<code>oldest</code>变量。最终循环后得到的<code>oldest</code>就是工龄最高的飞机师。</p>
<p>通过这几个例子，你可以看到使用<code>.reduce()</code>可以简单又优雅的在一个数组里面获取到单个最终值或者对象。</p>
<hr>
<h1 id="filter"><a href="#filter" class="headerlink" title=".filter()"></a>.filter()</h1><p>如果你现在的场景是需要在一个数组里面过滤一部分的数据，这个时候<code>.filter()</code>就是你的最好的朋友了。</p>
<p>我们用回飞机师的数据，并且加入了所属航空公司的值：</p>
<pre><code class="javascript">var pilots = [
  {
    id: 2,
    name: &quot;Wedge Antilles&quot;,
    faction: &quot;Rebels&quot;,
  },
  {
    id: 8,
    name: &quot;Ciena Ree&quot;,
    faction: &quot;Empire&quot;,
  },
  {
    id: 40,
    name: &quot;Iden Versio&quot;,
    faction: &quot;Empire&quot;,
  },
  {
    id: 66,
    name: &quot;Thane Kyrell&quot;,
    faction: &quot;Rebels&quot;,
  }
];</code></pre>
<p>加入现在我们想分别筛选出<code>Rebels</code>和<code>Empire</code>两个航空公司的飞机师，使用<code>.filter()</code>就是轻而易举的事情！</p>
<pre><code class="javascript">var rebels = pilots.filter(function (pilot) {
  return pilot.faction === &quot;Rebels&quot;;
});
var empire = pilots.filter(function (pilot) {
  return pilot.faction === &quot;Empire&quot;;
});</code></pre>
<p>就这么简单，如果使用箭头方法（ES6）就更加优雅了：</p>
<pre><code class="javascript">const rebels = pilots.filter(pilot =&gt; pilot.faction === &quot;Rebels&quot;);
const empire = pilots.filter(pilot =&gt; pilot.faction === &quot;Empire&quot;);</code></pre>
<p>其实原理很简单，只要你的回调方法返回的是<code>true</code>，这个值或者对象就会在新的数组里面了。如果返回的是<code>false</code>就会被过滤掉了。</p>
<hr>
<h1 id="结合使用-map-，-reduce-，-filter"><a href="#结合使用-map-，-reduce-，-filter" class="headerlink" title="结合使用 .map()，.reduce()，.filter()"></a>结合使用 .map()，.reduce()，.filter()</h1><p>既然我们刚刚学到的三个函数都是可以用于数组的，并且<code>.map()</code>和<code>.filter()</code>都是返回数组的。那我们就可以串联起来使用。不说多了上代码试试！</p>
<p>我们用一个有趣一点的数据试验一下，假如现在我们有一个<code>星球大战</code>里面的<code>人物</code>的数组。每个字段的定义如下：</p>
<blockquote>
<ul>
<li><code>Id</code>: 人物唯一ID</li>
<li><code>name</code>: 人物名字</li>
<li><code>pilotingScore</code>: 飞行能力指数</li>
<li><code>shootingScore</code>: 射击能力指数</li>
<li><code>isForceUser</code>: 是否拥有隔空操控能力</li>
</ul>
</blockquote>
<p>我们的目标：获取<code>拥有隔空操控能力的飞行员的总飞行能力指数</code>。我们先分开一步一步实现这个目标！</p>
<ul>
<li>首先我们需要先获取到拥有隔空操控能力的飞行员。</li>
</ul>
<pre><code class="javascript">var jediPersonnel = personnel.filter(function (person) {
  return person.isForceUser;
});
// 结果集: [{...}, {...}, {...}] (Luke, Ezra and Caleb)</code></pre>
<ul>
<li>这段代码我们获得了3个飞行员对象，分别都是拥有隔空操控能力的飞行员。使用这个对象我们来获取每个飞行员的飞行能力指数值。</li>
</ul>
<pre><code class="javascript">var jediScores = jediPersonnel.map(function (jedi) {
  return jedi.pilotingScore + jedi.shootingScore;
});
// 结果: [154, 110, 156]</code></pre>
<ul>
<li>获取到每个飞行员的飞行能力指数值后，我们就可以用累加器（<code>.reduce()</code>）获取总飞行能力指数了。</li>
</ul>
<pre><code class="javascript">var totalJediScore = jediScores.reduce(function (acc, score) {
  return acc + score;
}, 0);
// 结果: 420</code></pre>
<p>这里分开实现方式可以达到我们的目标，但是其实我们可以串联起来，可以写的更加简洁又优雅！我们来玩玩更好玩的吧！</p>
<pre><code class="javascript">var totalJediScore = personnel
  .filter(function (person) {
    return person.isForceUser;
  })
  .map(function (jedi) {
    return jedi.pilotingScore + jedi.shootingScore;
  })
  .reduce(function (acc, score) {
    return acc + score;
  }, 0);</code></pre>
<p>这样写是不是很优雅！都被这段代码给美到了！❤️</p>
<p>如果我们使用箭头写法ES6，就更加优雅了！</p>
<pre><code class="javascript">const totalJediScore = personnel
  .filter(person =&gt; person.isForceUser)
  .map(jedi =&gt; jedi.pilotingScore + jedi.shootingScore)
  .reduce((acc, score) =&gt; acc + score, 0);</code></pre>
<p>哇！代码原来可以写的那么优雅的么？！想不到吧？</p>
<blockquote>
<p>其实我们只需要使用<code>.reduce()</code>就可以得到我们的目标结果了，以上例子做为教学例子，所以使用了3个我们学到的函数。</p>
<p>我们来看看只用<code>.reduce()</code>怎么实现的，来我们一起来刷新一下三观吧！</p>
</blockquote>
<pre><code class="javascript">const totalJediScore = personnel.reduce((acc, person) =&gt; person.isForceUser ? acc + person.pilotingScore + person.shootingScore : acc, 0);</code></pre>
<p>不敢想象吧？一行就搞定一个功能不是梦！</p>
<h1 id="为什么抛弃-forEach"><a href="#为什么抛弃-forEach" class="headerlink" title="为什么抛弃 .forEach()?"></a>为什么抛弃 .forEach()?</h1><p>其实我一开始写前端的时候也是一顿撸，来个数组都是撸个for循环，解决一切数组处理问题。但是近几年我开始步入前后端开发，API接口对接。发现数据处理越来越多，如果还是像以前那样什么都用for循环来处理数据，那其实数据处理的代码就会越来越臃肿越来越复杂凌乱。所以我开始抛弃了<code>.forEach()</code>。开始做一个优雅的程序员！</p>
<p>为什么使用<code>.map()</code>，<code>.filter()</code>，<code>.reduce()</code>写代码更优雅，更美观呢？我们用一个实战例子来对比一下吧。</p>
<p>假设现在我们对接一个接口，返回的数组里面有两个字段<code>name：人的名称</code>和<code>title：对应的职位</code>。</p>
<pre><code class="javascript">var data = [
  {
    name: &quot;Jan Dodonna&quot;,
    title: &quot;General&quot;,
  },
  {
    name: &quot;Gial Ackbar&quot;,
    title: &quot;Admiral&quot;,
  },
]</code></pre>
<p>产品经理给到你的需求是只需要展示这些人的职位称呼。</p>
<blockquote>
<p>当然这个时候有一些前端就会说“我只是个小小的前端，后端给我处理吧”。但是，这个接口其实是一个通用的接口，就是获取这些员工的资料的，是在多个地方使用的。如果每一个页面因为需要展示的不一样而要写多一个接口给你，你觉得这样好吗？做为一个优秀的前端工程师🦁️，这种小case你自己就可以很优雅的处理好了。而且，在一个优秀的团队，后端确实是要考虑接口通用性的，这种为了你的方便而给他们带来更臃肿的接口是不可接受的。所以前端这个时候就是要重组数据了。</p>
</blockquote>
<p>假设现在产品给你的需求是员工列表展示，要支持只展示员工职称和员工左右信息的两种显示项。这个时候我们就要编写一个数据组装方法来跟进展示要求来改变数据格式。</p>
<p>因为这个“神马“的需求，我们使用<code>.forEach()</code>来重组数据就相对比较麻烦了，而且代码也会变得臃肿。</p>
<p>我们忽略了组装数据的方法，直接就当作我们已经写好了一个组装数据的方法为<code>formatElement</code>。如果我们用<code>forEach</code>首先我们就需要定义一个空数组来接收结果。</p>
<pre><code class="javascript">var results = [];
data.forEach(function (element) {
  var formatted = formatElement(element);
  results.push(formatted);
});</code></pre>
<p>所以我们需要两个方法才能实现这个数据结果，但是为什么要写的那么臃肿呢？因为<code>forEach</code>并没有返回值，单单就给你跑个循环，还需要自己<code>push</code>值到预定义的变量里面。其实一个方法就可以完成了，而且重点是一行代码就完事了。</p>
<p>来使用我们新学的技巧，用<code>.map()</code>来实现就非常简单优雅了。</p>
<pre><code class="javascript">var results = data.map(formatElement);</code></pre>
<h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>你学会了吗？学会了就去尝试用<code>.map()</code>，<code>.reduce()</code>，<code>.filter()</code>来替换你传统的<code>for</code>循环吧！我保证你的代码会越来越简洁，可读性更高。</p>
<p>如果你喜欢我的这遍文章，记得继续关注我的博客，下一遍文章我们开学习怎么在JavaScript中使用<code>.some()</code>和<code>.find()</code>。</p>
<p>坚持做一个优雅的程序员，坚持每天敲代码！</p>

            <!--[if lt IE 9]><script>document.createElement('audio');</script><![endif]-->
            <audio id="audio" loop="1" preload="auto" controls="controls"
                data-autoplay="false">
                <source type="audio/mpeg" src="">
            </audio>
            
            <ul id="audio-list" style="display:none">
                
                
                <li title='0' data-url='/statics/chengdu.mp3'></li>
                
                    
            </ul>
            
            
            
    <div id='gitalk-container' class="comment link"
        data-ae='true'
        data-ci='ec894e2b66f752e8b7fb'
        data-cs='3ccc2e92bb350688fe2c2dc2930189b62622bfb1'
        data-r='blog-comments'
        data-o='TriDiamond'
        data-a='TriDiamond'
        data-d=''
    >留言</div>


            
            
        </div>
        <div class="sidebar">
            <div class="box animated fadeInRight">
                <div class="subbox">
                    <img src="https://res.cloudinary.com/tridiamond/image/upload/v1573019751/TriDiamond_logo_ui_xeublz.jpg" height=300 width=300></img>
                    <p>三·钻 TriDiamond</p>
                    <span>Think like an artist, develop like an artisan</span>
                    <dl>
                        <dd><a href="https://github.com/TriDiamond" target="_blank"><span
                                    class=" iconfont icon-github"></span></a></dd>
                        <dd><a href="https://twitter.com/TriDiamond6" target="_blank"><span
                                    class=" iconfont icon-twitter"></span></a></dd>
                        <dd><a href="https://stackoverflow.com/users/7602324/tridiamond?tab=profile" target="_blank"><span
                                    class=" iconfont icon-stack-overflow"></span></a></dd>
                    </dl>
                </div>
                <ul>
                    <li><a href="/">14 <p>文章</p></a></li>
                    <li><a href="/categories">8 <p>分类</p></a></li>
                    <li><a href="/tags">20 <p>标签</p></a></li>
                </ul>
            </div>
            
            
            
            <div class="box sticky animated fadeInRight faster">
                <div id="toc" class="subbox">
                    <h4>目录</h4>
                    <ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link" href="#map"><span class="toc-number">1.</span> <span class="toc-text">.map()</span></a></li><li class="toc-item toc-level-1"><a class="toc-link" href="#reduce"><span class="toc-number">2.</span> <span class="toc-text">.reduce()</span></a></li><li class="toc-item toc-level-1"><a class="toc-link" href="#filter"><span class="toc-number">3.</span> <span class="toc-text">.filter()</span></a></li><li class="toc-item toc-level-1"><a class="toc-link" href="#结合使用-map-，-reduce-，-filter"><span class="toc-number">4.</span> <span class="toc-text">结合使用 .map()，.reduce()，.filter()</span></a></li><li class="toc-item toc-level-1"><a class="toc-link" href="#为什么抛弃-forEach"><span class="toc-number">5.</span> <span class="toc-text">为什么抛弃 .forEach()?</span></a></li><li class="toc-item toc-level-1"><a class="toc-link" href="#总结"><span class="toc-number">6.</span> <span class="toc-text">总结</span></a></li></ol>
                </div>
            </div>
            
            
        </div>
    </div>
</div>

    </div>
</div>
    <div id="back-to-top" class="animated fadeIn faster">
        <div class="flow"></div>
        <span class="percentage animated fadeIn faster">0%</span>
        <span class="iconfont icon-top02 animated fadeIn faster"></span>
    </div>
</body>
<footer>
    <p class="copyright" id="copyright">
        &copy; 2019
        <span class="gradient-text">
            三·钻 TriDiamond
        </span>.
        Powered by <a href="http://hexo.io/" title="Hexo" target="_blank" rel="noopener">Hexo</a>
        Theme
        <span class="gradient-text">
            <a href="https://github.com/TriDiamond/hexo-theme-obsidian" title="Obsidian" target="_blank" rel="noopener">Obsidian</a>
        </span>
        <small><a href="https://github.com/TriDiamond/hexo-theme-obsidian/blob/master/CHANGELOG.md" title="v1.4.3" target="_blank" rel="noopener">v1.4.3</a></small>
    </p>
</footer>

<script type="text/javascript" src="https://cdn.bootcss.com/mathjax/2.7.6/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
</script>
<script>
  MathJax.Hub.Config({
    "HTML-CSS": {
      preferredFont: "TeX",
      availableFonts: ["STIX", "TeX"],
      linebreaks: {
        automatic: true
      },
      EqnChunk: (MathJax.Hub.Browser.isMobile ? 10 : 50)
    },
    tex2jax: {
      inlineMath: [
        ["$", "$"],
        ["\\(", "\\)"]
      ],
      processEscapes: true,
      ignoreClass: "tex2jax_ignore|dno",
      skipTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code']
    },
    TeX: {
      noUndefined: {
        attributes: {
          mathcolor: "red",
          mathbackground: "#FFEEEE",
          mathsize: "90%"
        }
      },
      Macros: {
        href: "{}"
      }
    },
    messageStyle: "none"
  });
</script>
<script>
  function initialMathJax() {
    MathJax.Hub.Queue(function () {
      var all = MathJax.Hub.getAllJax(),
        i;
      // console.log(all);
      for (i = 0; i < all.length; i += 1) {
        console.log(all[i].SourceElement().parentNode)
        all[i].SourceElement().parentNode.className += ' has-jax';
      }
    });
  }

  function reprocessMathJax() {
    if (typeof MathJax !== 'undefined') {
      MathJax.Hub.Queue(["Typeset", MathJax.Hub]);
    }
  }
</script>



    <link rel="stylesheet" href="//cdn.bootcss.com/gitalk/1.5.0/gitalk.min.css">
    <script src="//cdn.bootcss.com/gitalk/1.5.0/gitalk.min.js"></script>

<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="/js/plugin.js"></script>
<script src="/js/obsidian.js"></script>
<script src="/js/jquery.truncate.js"></script>
<script src="/js/search.js"></script>
<script src="//cdn.bootcss.com/typed.js/2.0.10/typed.min.js"></script>
<script src="//cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/social-share.js/1.0.16/js/social-share.min.js"></script>

<script src="https://cdn.bootcss.com/codemirror/5.48.4/codemirror.min.js"></script>

    <script src="//cdn.bootcss.com/codemirror/5.48.4/mode/javascript/javascript.min.js"></script>

    <script src="//cdn.bootcss.com/codemirror/5.48.4/mode/css/css.min.js"></script>

    <script src="//cdn.bootcss.com/codemirror/5.48.4/mode/xml/xml.min.js"></script>

    <script src="//cdn.bootcss.com/codemirror/5.48.4/mode/htmlmixed/htmlmixed.min.js"></script>

    <script src="//cdn.bootcss.com/codemirror/5.48.4/mode/clike/clike.min.js"></script>

    <script src="//cdn.bootcss.com/codemirror/5.48.4/mode/php/php.min.js"></script>

    <script src="//cdn.bootcss.com/codemirror/5.48.4/mode/shell/shell.min.js"></script>

    <script src="//cdn.bootcss.com/codemirror/5.48.4/mode/python/python.min.js"></script>



    <script src="/js/busuanzi.min.js"></script>
    <script>
        $(document).ready(function () {
            if ($('span[id^="busuanzi_"]').length) {
                initialBusuanzi();
            }
        });
    </script>


<link rel="stylesheet" href="//cdn.bootcss.com/photoswipe/4.1.3/photoswipe.min.css">
<link rel="stylesheet" href="//cdn.bootcss.com/photoswipe/4.1.3/default-skin/default-skin.min.css">
<script src="//cdn.bootcss.com/photoswipe/4.1.3/photoswipe.min.js"></script>
<script src="//cdn.bootcss.com/photoswipe/4.1.3/photoswipe-ui-default.min.js"></script>

<!-- Root element of PhotoSwipe. Must have class pswp. -->
<div class="pswp" tabindex="-1" role="dialog" aria-hidden="true">
    <!-- Background of PhotoSwipe. 
         It's a separate element as animating opacity is faster than rgba(). -->
    <div class="pswp__bg"></div>
    <!-- Slides wrapper with overflow:hidden. -->
    <div class="pswp__scroll-wrap">
        <!-- Container that holds slides. 
            PhotoSwipe keeps only 3 of them in the DOM to save memory.
            Don't modify these 3 pswp__item elements, data is added later on. -->
        <div class="pswp__container">
            <div class="pswp__item"></div>
            <div class="pswp__item"></div>
            <div class="pswp__item"></div>
        </div>
        <!-- Default (PhotoSwipeUI_Default) interface on top of sliding area. Can be changed. -->
        <div class="pswp__ui pswp__ui--hidden">
            <div class="pswp__top-bar">
                <!--  Controls are self-explanatory. Order can be changed. -->
                <div class="pswp__counter"></div>
                <button class="pswp__button pswp__button--close" title="Close (Esc)"></button>
                <button class="pswp__button pswp__button--share" title="Share"></button>
                <button class="pswp__button pswp__button--fs" title="Toggle fullscreen"></button>
                <button class="pswp__button pswp__button--zoom" title="Zoom in/out"></button>
                <!-- Preloader demo http://codepen.io/dimsemenov/pen/yyBWoR -->
                <!-- element will get class pswp__preloader--active when preloader is running -->
                <div class="pswp__preloader">
                    <div class="pswp__preloader__icn">
                      <div class="pswp__preloader__cut">
                        <div class="pswp__preloader__donut"></div>
                      </div>
                    </div>
                </div>
            </div>
            <div class="pswp__share-modal pswp__share-modal--hidden pswp__single-tap">
                <div class="pswp__share-tooltip"></div> 
            </div>
            <button class="pswp__button pswp__button--arrow--left" title="Previous (arrow left)">
            </button>
            <button class="pswp__button pswp__button--arrow--right" title="Next (arrow right)">
            </button>
            <div class="pswp__caption">
                <div class="pswp__caption__center"></div>
            </div>
        </div>
    </div>
</div>



    <!-- Global site tag (gtag.js) - Google Analytics -->
    <script async src="//www.googletagmanager.com/gtag/js?id=UA-149874671-1"></script>
    <script>
        window.dataLayer = window.dataLayer || [];
        function gtag(){dataLayer.push(arguments);}
        gtag('js', new Date());

        gtag('config', 'UA-149874671-1');
    </script>





<script>
    function initialTyped () {
        var typedTextEl = $('.typed-text');
        if (typedTextEl && typedTextEl.length > 0) {
            var typed = new Typed('.typed-text', {
                strings: ["Think like an artist, develop like an artisan", "艺术家思维去思考问题，工匠创造精神去开发"],
                typeSpeed: 90,
                loop: true,
                loopCount: Infinity,
                backSpeed: 20,
            });
        }
    }

    if ($('.article-header') && $('.article-header').length) {
        $(document).ready(function () {
            initialTyped();
        });
    }
</script>




</html>
